/*
 * Copyright (c) 2022 Huawei Device Co., Ltd.
 * Licensed under the Apache License,Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import CommonLog from "./CommonLog"
import deviceManager from '@ohos.distributedHardware.deviceManager';
import { DeviceInfo, RemoteDeviceStatus } from "./model/DeviceInfo"
import prompt from '@system.prompt'


// 以下不能为空
const APP_NAME = "MyOpenHarmonyPlayer"
const APP_DESCRIPTION = "MyOpenHarmonyPlayer"

/**
 * 设备管理类，用于发现设备，认证设备
 */
export class RemoteDeviceManager {
    // 设备管理器
    private dmInstance = null
    // 设备列表
    private deviceList: DeviceInfo[] = []
    public bundleName = ""
    // 随机生成订阅id
    private subscribeId: number = 1000
    private isDiscovering: boolean = false

    /**
     * 构造函数，传入@State 或者 @Provide 装饰的设备列表数据
     * 不能对deviceList进行重新赋值，否则将不能动态更新视图
     */
    constructor(deviceList: DeviceInfo[]) {
        this.deviceList = deviceList
    }

    /**
     * 初始化，创建deviceManager对象，返回Promise对象
     */
    async init(): Promise<any> {
        return new Promise((resolve, reject) => {
            if (this.dmInstance !== null) {
                resolve(this.dmInstance)
            }

            // @ts-ignore
            deviceManager.createDeviceManager(this.bundleName, (error, dm) => {
                if (error) {
                    CommonLog.error('deviceManager.createDeviceManager failed:' + error);
                    reject(error)
                }
                this.dmInstance = dm

                // 注册设备上线下线监听
                this.dmInstance.on('deviceStateChange', (data) => {
                    // todo fix 目前看设备新认时，设备名字和id都有可能变化，导致无法修改现有deviceList
                    CommonLog.info('deviceStateChange data=' + JSON.stringify(data));
                    switch (data.action) {
                    // ONLINE
                        case 0:
                            CommonLog.info('ONLINE a device ! deviceInfo=' + JSON.stringify(data.device))
                            for (let i = 0; i < this.deviceList.length; i++) {
                                if (this.deviceList[i].deviceId == data.device.deviceId) {
                                    // 无法检测到深层数据变化，需要将对象拷贝重新赋值
                                    let device = Object.assign(this.deviceList[i], {}) as DeviceInfo
                                    device.status = RemoteDeviceStatus.ONLINE
                                    device.deviceId = data.device.deviceId
                                    this.deviceList[i] = device
                                    CommonLog.info('Update a online device: ' + JSON.stringify(device))
                                    this.forcedUpdateList()
                                    return
                                }
                            }

                            let newDevice: DeviceInfo = {
                                deviceId: data.device.deviceId,
                                deviceName: data.device.deviceName,
                                deviceType: data.device.deviceType,
                                networkId: data.device.networkId,
                                status: RemoteDeviceStatus.ONLINE
                            }
                            CommonLog.info('Found a new online device: deviceName=' + JSON.stringify(newDevice))
                            this.deviceList.push(newDevice);
                            break;
                    // OFFLINE
                        case 2:
                            CommonLog.info('OFFLINE a device! deviceInfo=' + JSON.stringify(data.device))
                            for (let i = 0; i < this.deviceList.length; i++) {
                                if (this.deviceList[i].deviceId == data.device.deviceId) {
                                    CommonLog.info('Delete a offline device: deviceName=' + this.deviceList[i].deviceName)
                                    this.deviceList.splice(i, 1) // 删除当前设备
                                    return
                                }
                            }
                            CommonLog.info('Not found this offline device in deviceList: ' + data.device.deviceName)
                            break;
                    // READY
                        case 1:
                            CommonLog.info('READY')
                            break;
                        default:
                            break;
                    }
                })

                this.dmInstance.on('deviceFound', (data) => {
                    CommonLog.info('deviceFound  ' + JSON.stringify(data))
                    for (let i = 0; i < this.deviceList.length; i++) {
                        if (this.deviceList[i].deviceId == data.device.deviceId) {
                            this.deviceList[i].deviceId = data.device.deviceId
                            CommonLog.info('deviceFound device founded in deviceList, update deviceId');
                            return;
                        }
                    }
                    data.device.status = RemoteDeviceStatus.UNTRUSTED
                    this.deviceList.push(data.device);
                })

                this.dmInstance.on('discoverFail', (data) => {
                    CommonLog.info('discoverFail  ' + JSON.stringify(data))
                });
                this.dmInstance.on('serviceDie', (data) => {
                    CommonLog.info('serviceDie  ' + JSON.stringify(data))
                });

                // 获取信任列表
                let list = this.dmInstance.getTrustedDeviceListSync()
                CommonLog.info('getTrustedDeviceListSync ' + JSON.stringify(list))
                if (list && list.length) {
                    for (let device of list) {
                        device.status = RemoteDeviceStatus.ONLINE
                        this.deviceList.push(device)
                    }
                }

                resolve(this.dmInstance)
            })
        })
    }

    startDeviceDiscovery() {
        CommonLog.info('before startDeviceDiscovery!')
        if (this.isDiscovering === true) {
            CommonLog.info('has already startDeviceDiscovery!')
            return
        }

        this.init().then(() => {
            CommonLog.info('startDeviceDiscovery after init!')
            // 使用相同的Id，若之前没有正常停止会导致第二次不能正常发现设备
            this.subscribeId = Math.floor(Math.random() * 10000 + 1000);

            let info = {
                "subscribeId": this.subscribeId,
                "mode": 0xAA,
                "medium": 0,
                "freq": 2,
                "isSameAccount": false,
                "isWakeRemote": true,
                "capability": 0
            }
            CommonLog.info(JSON.stringify(info))
            this.dmInstance.startDeviceDiscovery(info)
            this.isDiscovering = true
        })
    }

    stopDeviceDiscovery() {
        if (this.isDiscovering === false || this.dmInstance === null) {
            return
        }
        this.dmInstance.stopDeviceDiscovery(this.subscribeId)
        this.isDiscovering = false
    }

    releaseDeviceManager() {
        if (this.dmInstance != null) {
            this.dmInstance.off('deviceStateChange')
            this.dmInstance.off('serviceDie')
            this.dmInstance.off('deviceFound')
            this.dmInstance.off('discoverFail')
            this.stopDeviceDiscovery()
            this.dmInstance.release()
            this.dmInstance = null
        }
    }

    /**
     * 认证设备
     * @param remoteDevice 远程设备
     */
    async authDevice(remoteDevice: DeviceInfo) {
        CommonLog.info("authDevice:deviceName=" + remoteDevice.deviceName + " deviceId=" + remoteDevice.deviceId)

        return new Promise((resolve, reject) => {
            if (remoteDevice.status != RemoteDeviceStatus.UNTRUSTED) {
                CommonLog.info("authDevice:device already certified")
                resolve("Already certified")
            }
            // 认证
            let extraInfo = {
                "targetPkgName": this.bundleName,
                "appName": APP_NAME,
                "appDescription": APP_DESCRIPTION,
                "business": '0'
            };
            let authParam = {
                "authType": 1,
                "appIcon": '',
                "appThumbnail": '',
                "extraInfo": extraInfo
            }
            CommonLog.info("authDevice:start")
            this.dmInstance.authenticateDevice(remoteDevice, authParam, (err, data) => {
                if (err) {
                    CommonLog.info(' authenticateDevice failed, err=' + JSON.stringify(err))
                    prompt.showToast({ message: 'authenticateDevice failed, err=' + JSON.stringify(err) })
                    reject("fail") // 认证失败
                } else {
                    CommonLog.info('authenticateDevice succeed, data=' + JSON.stringify(data))
                    resolve("success") // 认证成功
                }
            })
            CommonLog.info("authDevice:end")
        })
    }

    /**
     * 强制更新deviceList UI视图
     */
    forcedUpdateList() {
        let temp: DeviceInfo = {
            "deviceId": "string",
            "deviceName": "string",
            "networkId": "string",
            "deviceType": 0,
            "status": RemoteDeviceStatus.UNTRUSTED
        };

        this.deviceList.push(temp)

        this.deviceList.pop()
    }
}